home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / pascal / inline22.zip / INLINE.PAS < prev    next >
Pascal/Delphi Source File  |  1989-03-04  |  57KB  |  2,094 lines

  1.                            {Inline28}
  2.  
  3. (*********  Source code Copyright 1986, by L. David Baldwin   *********)
  4.  
  5. {$R-,S-,I+,F-,V-,B-,N-}
  6. {$M 16384,0,655360 }
  7.  
  8. {
  9. 28 Vers 2.20 Add Cdecl and code for __emit__().
  10.              Keep case of symbols intact, mostly for C.
  11.              Fix instructions like cmp cx,>abc which assembled as if abc
  12.                was a byte.
  13. 27 Vers 2.19 Fix CMP AX,-1, etc., incorrect in Vers 2.18.
  14. 26 Vers 2.18 Implement the sign extension bit for some instructions
  15. 25 Vers 2.17 Convert to Turbo 4.
  16. 24 Vers 2.16 Change byte size check in MemReg so the likes of
  17.              MOV [DI+$FE],AX will assemble right.
  18.    Allow ',' in DB pseudo op instruction.
  19. 23 Vers 2.15 Fix 'shl cl,1' which assembled as shl cl,cl
  20. 22 Vers 2.14 Change output format to better accomodate map file line numbers.
  21. 21 Vers 2.13 Allow JMP SHORT direct using symbols.
  22. 20 Vers 2.12 Allow CALL and JMP direct using symbols.
  23. 19 Vers 2.11
  24.    Fix bug in CallJmp and ShortJmp which didn't restrict short
  25.    jump range properly.
  26.    Fix bug which didn't allow CALL or JMP register. (CALL BX).
  27. 18 Vers 2.1
  28.    Fix bug in Accum which occasionally messed up IN and OUT instr.
  29.    Fix unintialized function in getnumber for quoted chars.
  30. 17 Vers 2.03
  31.     Change GetSymbol to accept about anything after '>' or '<'
  32.     Add 'NEW' pseudoinstruction.
  33.     Fix serious bug in defaultextension.
  34.     Add Wait_Already to prevent 2 'WAIT's from occuring.
  35.     Use 'tindex<maxbyte' comparison rather than <= which won't work
  36.     with integer comparison in this cazse.
  37. }
  38.  
  39. PROGRAM Inline_Asm;
  40. Const
  41.   InString : String[11] = 'Inline('^M^J;
  42.   Separate : Char = '/';
  43.   StartComment : String[2] = '{';
  44.   EndComment : String[4] = '}'^M^J;
  45.   HexLeader : String[2] = '$';
  46.  
  47. Const
  48.   Cdecl : Boolean = False;
  49.   CommentColumn = 25;     {column where comments start in object file}
  50.   Symbolleng = 32;        {maximum of 32 char symbols}
  51.   CR = 13; Lf = 10; Tab = 9;
  52.   Maxbyte = MaxInt;
  53.   BigStringSize = 127;
  54.  
  55.   Signon1 : String[32] =
  56.  
  57.             ^M^J'Inline Assembler, Vers 2.20';
  58.  
  59.   Signon2 : String[43] =
  60.  
  61.             ^M^J'(C) Copyright 1986-7 by L. David Baldwin'^M^J;
  62.  
  63. Type
  64.   FileString = String[64];
  65.   SymString = String[Symbolleng];
  66.   IndxReg = (BX, SI, DI, BP, None);
  67.   IndxSet = set of IndxReg;
  68.   PtrType = (BPtr, WPtr, DwPtr, QwPtr, TbPtr, UnkPtr); {keep order}
  69.   String4 = String[4];
  70.   String5 = Array[1..5] of Char;
  71.   Symtype = (Address, Disp8, Disp16, Othersym, EOLsym, Identifier, JmpDist,
  72.     LfBrack, RtBrack, Plus, Comma, STsym);
  73.   Table = Array[0..20] of SymString; {fake}
  74.   BigString = String[BigStringSize]; {125 chars on a turbo line}
  75.   Label_Info_ptr = ^Label_Info;
  76.   Label_Info = Record
  77.                  Name : SymString;
  78.                  ByteCnt : Integer;
  79.                  Next : Label_Info_ptr;
  80.                end;
  81.   Fixup_Info_Ptr = ^Fixup_Info;
  82.   Fixup_Info = Record
  83.                  Name : SymString;
  84.                  Indx, Indx2, Fix_pt : Integer;
  85.                  Jmptype : (Short, Med);
  86.                  Prev, Next : Fixup_Info_Ptr;
  87.                end;
  88.  
  89. Var
  90.   NoAddrs, Aerr, Symbol, TheEnd, NewFnd, St_first,
  91.   Displace, WordSize, Wait_Already : Boolean;
  92.   Addr : Integer;
  93.   Sym : Symtype;
  94.   ModeByte, Reg1, Reg2, W1, W2, Sti_val : Integer;
  95.   SaveOfs, DataVal : Record
  96.                        Symb : Boolean;
  97.                        Sname : SymString;
  98.                        Value : Integer;
  99.                      end;
  100.   IRset : IndxSet;
  101.   Rmm, Md : Integer;
  102.   ByWord : PtrType;
  103.   Byt, SignExt : Byte;
  104.   Tindex, Tindex0, Column, I, ByteCount, LastSlash : Integer;
  105.   TextArray : Array[0..Maxbyte] of Char;
  106.  
  107.   Lsid : SymString;
  108.   Str8 : Array[1..9] of Char; {the following 4 are at the same location}
  109.   Str : String5 Absolute Str8;
  110.   ID2 : Array[1..2] of Char Absolute Str8;
  111.   ID3 : Array[1..3] of Char Absolute Str8;
  112.   UCh, LCh : Char;
  113.   Chi, OldChi : Integer;
  114.   Out, Inn : Text;
  115.  
  116.   Start_Col : Integer;
  117.   St : BigString;
  118.   Firstlabel, Pl : Label_Info_ptr;
  119.   Firstfix, Pf : Fixup_Info_Ptr;
  120.   ZeroX : Boolean;
  121.  
  122. {-------------DefaultExtension}
  123. PROCEDURE DefaultExtension(Extension:FileString;Var Infile,Name :FileString);
  124. {Given a filename, infile, add a default extension if none exists. Return
  125.  also the name without any extension.}
  126. Var
  127.  I,J : Integer;
  128.  Temp : FileString;
  129. begin
  130. I:=Pos('..',Infile);
  131. if I=0 then
  132.   Temp:=Infile
  133. else
  134.   begin   {a pathname starting with ..}
  135.   Temp:=Copy(Infile,I+2,64);
  136.   I:=I+1;
  137.   end;
  138. J:=Pos('.',Temp);
  139. if J=0 then
  140.   begin
  141.   Name := Infile;
  142.   Infile:=Infile+'.'+Extension;
  143.   end
  144. else Name:=Copy(Infile,1,I+J-1);
  145. end;
  146.  
  147. {-------------Space}
  148. PROCEDURE Space(N : Integer);
  149. Var I : Integer;
  150. begin for I := 1 to N do Write(' '); end;
  151.  
  152. {-------------Error}
  153. PROCEDURE Error(II : Integer; S : BigString);
  154. begin
  155. if not Aerr then
  156.   begin
  157.   WriteLn(St);
  158.   Space(Start_Col+II-4);
  159.   Write('^Error');
  160.   if Length(S) > 0 then
  161.     begin Write(', '); Write(S); end;
  162.   WriteLn;
  163.   Aerr := True;
  164.   end;
  165. end;
  166.  
  167. {the following are definitions and variables for the parser}
  168. Var
  169.   Segm, NValue : Integer;
  170.   Symname, LSymname : SymString;
  171. {end of parser defs}
  172.  
  173. {-------------GetCh}
  174. PROCEDURE GetCh;
  175.   {return next char in uch and lch with uch in upper case.}
  176. begin
  177. if Chi <= Ord(St[0]) then LCh := St[Chi] else LCh := Chr(CR);
  178. UCh := UpCase(LCh);
  179. ZeroX := False;
  180. if UCh = '0' then  {Look for the hex indicator '0X' }
  181.    ZeroX := (Chi < Length(St)) and (UpCase(St[Chi+1]) = 'X');
  182. Chi := Chi+1;
  183. end;
  184.  
  185. {-------------SkipSpaces}
  186. PROCEDURE SkipSpaces;
  187. begin
  188. while (UCh = ' ') or (UCh = Chr(Tab)) do GetCh;
  189. end;
  190.  
  191. {-------------GetDec}
  192. FUNCTION GetDec(Var V : Integer) : Boolean;
  193. Const Ssize = 8;
  194. Var
  195.   S : String[Ssize];
  196.   Getd : Boolean;
  197.   Code : Integer;
  198. begin
  199. Getd := False;
  200. S := '';
  201. while (UCh >= '0') and (UCh <= '9') do
  202.   begin
  203.   Getd := True;
  204.   if Ord(S[0]) < Ssize then S := S+UCh;
  205.   GetCh;
  206.   end;
  207. if Getd then
  208.   begin
  209.   Val(S, V, Code);
  210.   if Code <> 0 then Error(Chi, 'Bad number format');
  211.   end;
  212. GetDec := Getd;
  213. end;
  214.  
  215. {-------------GetHex}
  216. FUNCTION GetHex(Var H : Integer) : Boolean;
  217. Var Digit : Integer;        {check for '$' or '0x' before the call}
  218. begin
  219. H := 0; GetHex := False;
  220. while (UCh in ['A'..'F', '0'..'9']) do
  221.   begin
  222.   GetHex := True;
  223.   if (UCh >= 'A') then Digit := Ord(UCh)-Ord('A')+10
  224.     else Digit := Ord(UCh)-Ord('0');
  225.   if H and $F000 <>0 then Error(Chi, 'Overflow');
  226.   H := (H Shl 4)+Digit;
  227.   GetCh;
  228.   end;
  229. end;
  230.  
  231. {-------------GetNumber}
  232. FUNCTION GetNumber(Var N : Integer) : Boolean;
  233.   {get a number and return it in n}
  234. Var Term : Char;
  235.   Err : Boolean;
  236. begin
  237. N := 0;
  238. if UCh = '(' then GetCh;    {ignore ( }
  239. if (UCh = '''') or (UCh = '"') then
  240.   begin
  241.   GetNumber := True;
  242.   Term := UCh; GetCh; Err := False;
  243.   while (UCh <> Term) and not Err do
  244.     begin
  245.     Err := N and $FF00 <> 0;
  246.     N := (N Shl 8)+Ord(LCh);
  247.     GetCh;
  248.     if Err then Error(Chi, 'Overflow');
  249.     end;
  250.   GetCh;                    {use up termination char}
  251.   end
  252. else if (UCh = '$') or ZeroX then
  253.   begin                     {a hex number}
  254.   if ZeroX then GetCh;    {2 Chars for '0X'}
  255.   GetCh;
  256.   if not GetHex(N) then Error(Chi, 'Hex number exp');
  257.   GetNumber := True;
  258.   end
  259. else
  260.   GetNumber := GetDec(N);   {maybe a decimal number}
  261. if UCh = ')' then GetCh;    {ignore an ending parenthesis}
  262. end;
  263.  
  264. {-------------GetExpr}
  265. FUNCTION GetExpr(Var Rslt : Integer) : Boolean;
  266. Var
  267.   Rs1, Rs2, SaveChi : Integer;
  268.   Pos, Neg : Boolean;
  269. begin
  270. SaveChi := Chi;
  271. GetExpr := False;
  272. SkipSpaces;
  273. Neg := UCh = '-';
  274. Pos := UCh = '+';
  275. if Pos or Neg then GetCh;
  276. if GetNumber(Rs1) then
  277.   begin
  278.   GetExpr := True;
  279.   if Neg then Rs1 := -Rs1;
  280.   if (UCh = '+') or (UCh = '-') then
  281.     if GetExpr(Rs2) then
  282.       Rs1 := Rs1+Rs2;       {getexpr will take care of sign}
  283.   Rslt := Rs1;
  284.   end
  285. else
  286.   begin
  287.   Chi := SaveChi-1; GetCh;
  288.   end;
  289. end;
  290.  
  291. {$v+}
  292. {-------------GetSymbol}
  293. FUNCTION GetSymbol(Var S : SymString) : Boolean;
  294. {Read the next symbol without changing the case}
  295. Const Symchars : set of Char = ['A'..'Z', '0'..'9', '_', '+', '-','$','*','&'];
  296. begin
  297. if UCh in Symchars then
  298.   begin
  299.   GetSymbol := True;
  300.   S[0] := Chr(0);
  301.   while UCh in Symchars do
  302.     begin
  303.     if Ord(S[0]) < Symbolleng then S := S+LCh;
  304.     GetCh;
  305.     end
  306.   end
  307. else GetSymbol := False;
  308. end;
  309. {$v-}
  310.  
  311. {-------------GetAddress}
  312. FUNCTION GetAddress : Boolean;
  313. Var Result : Boolean;
  314.   SaveChi : Integer;
  315. begin
  316. Result := False; SaveChi := Chi;
  317. if GetExpr(Segm) then
  318.   begin
  319.   SkipSpaces;
  320.   if UCh = ':' then
  321.     begin
  322.     GetCh; SkipSpaces;
  323.     Result := GetExpr(NValue);
  324.     end;
  325.   end;
  326. GetAddress := Result;
  327. if not Result then
  328.   begin Chi := SaveChi-1; GetCh; end;
  329. end;
  330.  
  331. {-------------ErrNull}
  332. PROCEDURE ErrNull;
  333. begin Error(Chi, ''); end;
  334.  
  335. {-------------ErrIncorrect}
  336. PROCEDURE ErrIncorrect;
  337. begin Error(Chi, 'Incorrect or No Operand'); end;
  338.  
  339. {-------------SegmErr}
  340. PROCEDURE SegmErr;
  341. begin Error(Chi, 'Segm Reg not Permitted'); end;
  342.  
  343. {-------------WordReg}
  344. PROCEDURE WordReg;
  345. begin Error(Chi, 'Word Reg Exp'); end;
  346.  
  347. {-------------DataLarge}
  348. PROCEDURE DataLarge;
  349. begin Error(Chi, 'Data Too Large'); end;
  350.  
  351. {-------------Chk_BwPtr}
  352. PROCEDURE Chk_BwPtr;
  353. begin
  354. if ByWord >= DwPtr then Error(Chi, 'BYTE or WORD Req''d');
  355. end;
  356.  
  357. {-------------ByteSize}
  358. FUNCTION ByteSize(Val : Integer) : Boolean;
  359.   {return true if val is a byte}
  360. begin
  361. ByteSize := (Hi(Val) = 0) or (Val and $FF80 = $FF80);
  362. end;
  363.  
  364. {-------------ShortSize}
  365. FUNCTION ShortSize(Val : Integer) : Boolean;
  366.     {return true if val is ShortInt size}
  367. begin
  368. ShortSize := (Val >= -128) and (Val <= 127);
  369. end;
  370.  
  371. {-------------ReadByte}
  372. FUNCTION ReadByte : Boolean;
  373. Var Rb : Boolean;
  374. begin
  375. Rb := GetExpr(NValue);
  376. if Rb then
  377.   if ByteSize(NValue) then
  378.     Byt := Lo(NValue)
  379.   else DataLarge;
  380. ReadByte := Rb;
  381. end;
  382.  
  383. {-------------MatchSt}
  384. FUNCTION MatchSt(Var Table; Size, Maxindx : Integer; Var Indx : Integer) :
  385.   Boolean;                  {see if str8 matches any string in a table}
  386. Var Ca : Array[0..MaxInt] of Char Absolute Table;
  387.   Rslt : Boolean;
  388.  
  389.   FUNCTION EqArray(Var A1; N : Integer) : Boolean;
  390.   Type Bigarray = Array[1..MaxInt] of Char;
  391.   Var
  392.     B1 : Bigarray Absolute A1;
  393.     I : Integer;
  394.   begin
  395.   for I := 1 to N do
  396.     if B1[I] <> Str8[I] then
  397.       begin EqArray := False; Exit; end;
  398.   EqArray := Str8[N+1] = ' '; {must have blank on end for complete match}
  399. end;
  400.  
  401. begin
  402. Indx := 0; Rslt := False;
  403. while (Indx <= Maxindx) and not Rslt do
  404.   if EqArray(Ca[Indx*Size], Size) then
  405.     Rslt := True
  406.   else
  407.     Indx := Indx+1;
  408. MatchSt := Rslt;
  409. end;
  410.  
  411. {-------------GetString}
  412. PROCEDURE GetString;
  413.   {Fill in Lsid, str8, str, id2,id3.  The latter 4 are, in fact, all in the
  414.    same locations}
  415. Var I : Integer;
  416. begin
  417. SkipSpaces;
  418. Lsid := '          ';
  419. I := 1;
  420. if (UCh >= 'A') and (UCh <= 'Z') then
  421.   repeat
  422.     begin
  423.     if I <= Symbolleng then
  424.       begin Lsid[I] := UCh; I := I+1; end;
  425.     GetCh;
  426.     end;
  427.   until not ((UCh >= 'A') and (UCh <= 'Z') or (UCh >= '0') and (UCh <= '9'));
  428. Lsid[0] := chr(I-1);
  429. Move(Lsid[1], Str8, 9);     {Fill in str8,str,id2,id3}
  430. end;
  431.  
  432. {-------------InsertChr}
  433. PROCEDURE InsertChr(C : Char);
  434. begin
  435. if Tindex < Maxbyte then
  436.   begin
  437.   TextArray[Tindex] := C;
  438.   Tindex := Tindex+1; Column := Column+1;
  439.   end
  440. else
  441.   begin
  442.   WriteLn('Object Code Overflow!');
  443.   Halt(1);
  444.   end;
  445. end;
  446.  
  447. {-------------InsertStr}
  448. PROCEDURE InsertStr(S : BigString);
  449. Var I : Integer;
  450. begin
  451. for I := 1 to Ord(S[0]) do InsertChr(S[I]);
  452. end;
  453.  
  454. {-------------Hex2}
  455. FUNCTION Hex2(B : Byte) : String4;
  456. Const HexDigs : Array[0..15] of Char = '0123456789ABCDEF';
  457. Var Bz : Byte;
  458. begin
  459. Bz := B and $F; B := B Shr 4;
  460. Hex2 := HexDigs[B]+HexDigs[Bz];
  461. end;
  462.  
  463. {-------------Hex4}
  464. FUNCTION Hex4(W : Integer) : String4;
  465. begin Hex4 := Hex2(Lo(W))+Hex2(Hi(W)); end;
  466.  
  467. {-------------InsertByte}
  468. PROCEDURE InsertByte(B : Byte);
  469. begin
  470. InsertStr(HexLeader+Hex2(B));
  471. ByteCount := ByteCount+1;
  472. LastSlash:=Tindex;
  473. InsertChr(Separate);
  474. Wait_Already:=False;  {any byte inserted cancels a WAIT}
  475. end;
  476.  
  477. {-------------InsertWord}
  478. PROCEDURE InsertWord(W : Integer);
  479. begin
  480. InsertByte(Lo(W)); InsertByte(Hi(W));
  481. end;
  482.  
  483. {-------------InsertHi_Low}
  484. PROCEDURE InsertHi_Low(W : Integer);
  485.   {insert a word in reverse order}
  486. begin
  487. InsertByte(Hi(W)); InsertByte(Lo(W));
  488. end;
  489.  
  490. {-------------InsertWait}
  491. PROCEDURE InsertWait;
  492. begin  {Insert a 'WAIT' for Fl Pt only if none already input}
  493. if not Wait_Already then InsertByte($9B);
  494. end;
  495.  
  496. {-------------Modify_Byte}
  497. PROCEDURE Modify_Byte(I : Integer; Modify : Byte);
  498.   {Modify an ascii byte string in textarray by adding modify to its value}
  499. Var
  500.   St : String4;
  501.   J : Integer;
  502.  
  503.   FUNCTION HexToByte(I : Integer; Var J : Integer) : Byte;
  504.     {Starting at tindex, I, convert hex to a byte. return J, the tindex where
  505.      byte started}
  506.   Var
  507.     Result, Tmp : Byte;
  508.     K : Integer;
  509.     C : Char;
  510.     Done : Boolean;
  511.   begin
  512.   Result := 0;
  513.   Done := False;
  514.   While not Done do
  515.      begin
  516.      C := TextArray[I];
  517.      case C of
  518.         '1'..'9', 'A'..'F' : Done := True;
  519.         '0'  : if Cdecl and (TextArray[I+1] = 'x') then
  520.                   Inc(I,2)
  521.                else Done := True;
  522.         else Inc(I);
  523.         end;
  524.      end;
  525.  
  526.   J := I;
  527.   for K:=I to I+1 do
  528.     begin
  529.     C := TextArray[K];
  530.     if C <= '9' then Tmp := Ord(C)-Ord('0') else Tmp := Ord(C)-Ord('A')+10;
  531.     Result := (Result Shl 4)+Tmp;
  532.     end;
  533.   HexToByte := Result;
  534.   end;
  535.  
  536. begin
  537. St := Hex2(HexToByte(I, J)+Modify);
  538. TextArray[J] := St[1];
  539. TextArray[J+1] := St[2];
  540. end;
  541.  
  542. {-------------DoNext}
  543. PROCEDURE DoNext;
  544. Var TmpCh : Char;
  545.  
  546. begin
  547. OldChi := Chi;
  548. Symbol := False;
  549. if Sym = EOLsym then Exit;  {do nothing}
  550. SkipSpaces;                 {note commas are significant}
  551. if (UCh = Chr(CR)) or (UCh = ';') then Sym := EOLsym
  552. else if UCh = ',' then begin Sym := Comma; GetCh; end
  553. else if (UCh = '>') or (UCh = '<') then
  554.   begin
  555.   TmpCh := UCh; GetCh;
  556.   if not GetSymbol(LSymname) then Error(Chi, 'Symbol Name Exp');
  557.   if TmpCh = '<' then Sym := Disp8 else Sym := Disp16;
  558.   Symbol := True;           {disp8/16 is a symbol}
  559.   end
  560. else if GetAddress then
  561.   begin
  562.   if NoAddrs then ErrNull
  563.   else Sym := Address;
  564.   end
  565. else if GetExpr(NValue) then
  566.   begin
  567.   if ByteSize(NValue) then
  568.     Sym := Disp8 else Sym := Disp16;
  569.   end
  570. else if (UCh >= 'A') and (UCh <= 'Z') then
  571.   begin GetString; Symname := Lsid;
  572.   if (Lsid = 'FAR') or (Lsid = 'NEAR') or (Lsid = 'SHORT') then
  573.     Sym := JmpDist
  574.   else if Lsid = 'ST' then Sym := STsym
  575.   else Sym := Identifier;
  576.   end
  577. else if UCh = '+' then begin Sym := Plus; GetCh; end
  578. else if UCh = '[' then begin Sym := LfBrack; GetCh; end
  579. else if UCh = ']' then begin Sym := RtBrack; GetCh; end
  580. else begin Sym := Othersym; GetCh; end;
  581. end;
  582.  
  583. {-------------NextA}
  584. PROCEDURE NextA;            {Get the next item but also process any
  585.                             'WORD' 'BYTE', 'DWORD', 'QWORD',etc 'PTR'}
  586. Type Sizeary = Array[0..4] of String[2];
  587. Var Tmp : PtrType;
  588.   Indx : Integer;
  589. Const Ptrary : Sizeary = ('BY', 'WO', 'DW', 'QW', 'TB');
  590.       Ptrary1 : Array[0..4] of String[5] =
  591.                   ('BYTE','WORD','DWORD','QWORD','TBYTE');
  592.  
  593. begin
  594. DoNext;
  595. if Sym = Identifier then
  596.   begin
  597.   Tmp := BPtr; Indx := 0;
  598.   while (Tmp < UnkPtr) and (Lsid <> Ptrary[Indx]) and (Lsid <>Ptrary1[Indx]) do
  599.     begin
  600.     Tmp := Succ(Tmp); Indx := Indx+1;
  601.     end;
  602.   if Tmp < UnkPtr then
  603.     begin ByWord := Tmp; DoNext; end;
  604.   if Str = 'PTR  ' then DoNext; {ignore 'PTR'}
  605.   end;
  606. end;
  607.  
  608. {-------------Displace_Bytes}
  609. PROCEDURE Displace_Bytes(W : Integer);
  610. Var C : Char;
  611. begin
  612. if Displace then
  613.   with SaveOfs do
  614.     begin
  615.     if Symb then
  616.       begin                 {displacement is a symbol}
  617.       if Cdecl then InsertStr(Sname)
  618.       else
  619.         begin
  620.         if W = 1 then C := '>' else C := '<';
  621.         InsertStr(C+Sname);
  622.         end;
  623.       if Value <> 0 then    {Add it in too, don't reverse bytes}
  624.         InsertStr('+'+HexLeader+Hex2(Hi(Value))+Hex2(Lo(Value)));
  625.       if W = 1 then ByteCount := ByteCount+2 else ByteCount := ByteCount+1;
  626.       LastSlash:=Tindex;
  627.       InsertChr(Separate);
  628.       end
  629.     else
  630.       if W = 1 then InsertWord(Value) else InsertByte(Lo(Value));
  631.     end;
  632. end;
  633.  
  634. {-------------Data_Bytes}
  635. PROCEDURE Data_Bytes(WordSize : Boolean);
  636. Var S : String[15];
  637. begin
  638. with DataVal do
  639.   begin
  640.   if Symb then
  641.     begin                   {data is a symbol}
  642.     if Cdecl then
  643.        begin
  644.        if WordSize then
  645.           if Sname[1] = '&' then S := ''
  646.           else S := '(unsigned)'
  647.        else S := '(char)';
  648.        end
  649.     else
  650.        if WordSize then S := '>' else S := '<';
  651.     InsertStr(S+Sname);
  652.     if Value <> 0 then      {add it in too}
  653.       InsertStr('+'+HexLeader+Hex2(Hi(Value))+Hex2(Lo(Value)));
  654.     if WordSize then ByteCount := ByteCount+2 else ByteCount := ByteCount+1;
  655.     LastSlash:=Tindex;
  656.     InsertChr(Separate);
  657.     end
  658.   else
  659.     if WordSize then InsertWord(Value) else InsertByte(Lo(Value));
  660.   end;
  661. end;
  662.  
  663. {-------------GetIR}
  664. FUNCTION GetIR : Boolean;
  665. Var Reg : IndxReg;
  666. begin
  667. GetIR := False; Reg := None;
  668. if (Sym = Identifier) and (Lsid[0] = Chr(2)) then
  669.   if ID2 = 'BX' then Reg := BX
  670.   else if ID2 = 'SI' then Reg := SI
  671.   else if ID2 = 'DI' then Reg := DI
  672.   else if ID2 = 'BP' then Reg := BP;
  673. if Reg <> None then
  674.   begin
  675.   IRset := IRset+[Reg];
  676.   GetIR := True;
  677.   NextA;
  678.   end;
  679. end;
  680.  
  681. {-------------MemReg}
  682. FUNCTION MemReg(Var W : Integer) : Boolean;
  683. Label 10;
  684.  
  685.   {Does not handle the 'reg' part of the mem/reg. Returns disp true if
  686.   a displacement is found with w=0 for byte disp and w=1 for word
  687.   disp.  Any displacement is output in saveofs.}
  688.  
  689. Var
  690.   SaveChi : Integer;
  691.   Dsp16, OldAddrs, Result_MemReg : Boolean;
  692. begin
  693. SaveChi := OldChi; Dsp16 := False;
  694. Result_MemReg := False;
  695. OldAddrs := NoAddrs; NoAddrs := True;
  696. SaveOfs.Value := 0; SaveOfs.Symb := False; IRset := [];
  697. while (Sym <> Comma) and (Sym <> EOLsym) do {',' or cr terminate a MemReg}
  698.   begin
  699.   if Sym = LfBrack then
  700.     begin Result_MemReg := True; NextA; end;
  701.   if Sym = Plus then NextA;
  702.   if (Sym = Disp8) or (Sym = Disp16) then
  703.     with SaveOfs do
  704.       begin
  705.       Dsp16 := Dsp16 or (Sym = Disp16);
  706.       if Symbol then
  707.         begin
  708.         Symb := True; Sname := LSymname;
  709.         end
  710.       else Value := Value+NValue;
  711.       NextA;
  712.       end
  713.   else if not GetIR then
  714.     if Sym = RtBrack then NextA
  715.     else if Result_MemReg then
  716.       begin Error(Chi, 'Comma or Line End Exp'); NextA; end
  717.     else GOTO 10;           {abort}
  718.   end;
  719. if Result_MemReg then
  720.   begin                     {at least one '[' found}
  721.   if (IRset = []) or (IRset = [BP]) then Rmm := 6
  722.   else if IRset = [BX, SI] then Rmm := 0
  723.   else if IRset = [BX, DI] then Rmm := 1
  724.   else if IRset = [BP, SI] then Rmm := 2
  725.   else if IRset = [BP, DI] then Rmm := 3
  726.   else if IRset = [SI] then Rmm := 4
  727.   else if IRset = [DI] then Rmm := 5
  728.   else if IRset = [BX] then Rmm := 7
  729.   else Error(Chi, 'Bad Register Combination');
  730.  
  731.   NextA;                    {pass over any commas}
  732.   with SaveOfs do
  733.     Dsp16 := Dsp16 or (Symb and (Value <> 0)) or not ShortSize(Value);
  734.   if IRset = [] then
  735.     begin Displace := True; Md := 0; W := 1; end {direct address}
  736.   else if (IRset = [BP]) and not Dsp16 then
  737.     begin Displace := True; Md := 1; W := 0; end {bp must have displ}
  738.   else if (SaveOfs.Value = 0) and not SaveOfs.Symb then
  739.     begin Displace := False; Md := 0; W := 3; end
  740.   else if not Dsp16 then    {8 bit}
  741.     begin Displace := True; Md := 1; W := 0; end
  742.   else begin Displace := True; Md := 2; W := 1; end;
  743.   ModeByte := 64*Md+Rmm;
  744.   end
  745. else
  746. 10: begin                     {not a MemReg}
  747.   Chi := SaveChi-1; GetCh;  {restore as in beginning}
  748.   NextA;
  749.   end;
  750. NoAddrs := OldAddrs;
  751. MemReg := Result_MemReg;
  752. end;
  753.  
  754. {-------------St_St}
  755. FUNCTION St_St : Boolean;   {pick up st,st(i) or st(i),st or just st(i)}
  756. Var Err, Rslt : Boolean;
  757.  
  758.   FUNCTION GetSti_Val : Boolean;
  759.   Var Grslt : Boolean;
  760.   begin
  761.   NextA;
  762.   Grslt := Sym = Disp8;
  763.   if Grslt then
  764.     begin
  765.     Sti_val := NValue;
  766.     Err := ((Sti_val and $F8) <> 0); {check limit of 7}
  767.     NextA;
  768.     end;
  769.   GetSti_Val := Grslt;
  770.   end;
  771.  
  772. begin
  773. Err := False;
  774. Rslt := Sym = STsym;
  775. if Rslt then
  776.   begin
  777.   if GetSti_Val then
  778.     begin
  779.     St_first := False;      {st(i) is first}
  780.     while (Sym = Comma) or (Sym = STsym) do NextA;
  781.     end
  782.   else
  783.     begin
  784.     St_first := True;       {st preceeds st(i)}
  785.     if Sym = Comma then NextA;
  786.     if Sym = STsym then
  787.       begin
  788.       if not GetSti_Val then
  789.         Err := True;
  790.       end
  791.     else Err := True;
  792.     end;
  793.   if Err then ErrNull;
  794.   end;
  795. St_St := Rslt;
  796. end;
  797.  
  798. {-------------FstiOnly}
  799. FUNCTION FstiOnly : Boolean;
  800.   {Fl Pt instructions having only one form using st(i) operand}
  801.   {faddp,fmulp,fsubp,fsubrp,fdivp,fdivrp,ffree,fxch -- 0..7 }
  802. Type Arraytype = Array[0..7] of Word;
  803.   Table = Array[0..7, 0..5] of Char;
  804. Var Indx : Integer;
  805.   Rslt : Boolean;
  806. Const
  807.   Stiary : Arraytype =
  808.        ($DEC0, $DEC8, $DEE8, $DEE0, $DEF8, $DEF0, $DDC0, $D9C8);
  809.   StiOnlyTable : Table = ('FADDP ', 'FMULP ', 'FSUBP ',
  810.        'FSUBRP', 'FDIVP ', 'FDIVRP', 'FFREE ', 'FXCH  ');
  811.  
  812. begin
  813. Rslt := MatchSt(StiOnlyTable, 6, 7, Indx);
  814. if Rslt then
  815.   begin
  816.   NextA;
  817.   if not St_St then
  818.     begin
  819.     if Sym = EOLsym then Sti_val := 1
  820.     else ErrIncorrect;
  821.     end;
  822.   InsertWait;
  823.   InsertHi_Low(Stiary[Indx]+Sti_val);
  824.   end;
  825. FstiOnly := Rslt;
  826. end;
  827.  
  828. {-------------FmemOnly}
  829. FUNCTION FmemOnly : Boolean;
  830.   {Fl Pt instructions having only one form using a memory operand}
  831.   {fldenv,fldcw,fstenv,fstcw,fbstp,fbld,frstor,fsave,fstsw,
  832.   fnsave,fnstcw,fnstenv,fnstsw--0..12 }
  833. Type Arraytype = Array[0..12] of Word;
  834.   Table = Array[0..12, 0..6] of Char;
  835. Var Indx : Integer;
  836.   Rslt : Boolean;
  837. Const
  838.   Memary : Arraytype = (
  839.     $D920, $D928, $D930, $D938, $DF30, $DF20, $DD20, $DD30, $DD38,
  840.     $DD30, $D938, $D930, $DD38);
  841.   MemOnlyTable : Table =
  842.    ('FLDENV ', 'FLDCW  ', 'FSTENV ', 'FSTCW  ', 'FBSTP  ', 'FBLD   ',
  843.     'FRSTOR ', 'FSAVE  ', 'FSTSW  ',
  844.     'FNSAVE ', 'FNSTCW ', 'FNSTENV', 'FNSTSW ');
  845. begin
  846. Rslt := MatchSt(MemOnlyTable, 7, 12, Indx);
  847. if Rslt then
  848.   begin
  849.   NextA;
  850.   if Indx < 9 then InsertWait; {fwait}
  851.   if MemReg(W1) then
  852.     begin
  853.     InsertHi_Low(Memary[Indx]+ModeByte);
  854.     Displace_Bytes(W1);
  855.     end
  856.   else ErrIncorrect;
  857.   end;
  858. FmemOnly := Rslt;
  859. end;
  860.  
  861. {-------------FldType}
  862. FUNCTION FldType : Boolean;
  863.   {Do fld,fst,fstp-- 0..2}
  864. Type
  865.   Arraytype = Array[0..2, DwPtr..UnkPtr] of Word;
  866.   Table = Array[0..2, 0..3] of Char;
  867. Var Indx, Tmp : Integer;
  868.   Rslt : Boolean;
  869. Const
  870.   Fldarray : Arraytype = (
  871.     ($D900, $DD00, $DB28, $D9C0),
  872.     ($D910, $DD10, 0, $DDD0),
  873.     ($D918, $DD18, $DB38, $DDD8));
  874.   Fldtable : Table = ('FLD ', 'FST ', 'FSTP');
  875. begin
  876. Rslt := MatchSt(Fldtable, 4, 2, Indx);
  877. if Rslt then
  878.   begin
  879.   NextA;
  880.   InsertWait;           {fwait}
  881.   if ByWord >= DwPtr then
  882.     Tmp := Fldarray[Indx, ByWord];
  883.   if MemReg(W1) then
  884.     begin
  885.     if (ByWord >= DwPtr) and (ByWord <= TbPtr) then
  886.       begin
  887.       InsertHi_Low(Tmp+ModeByte);
  888.       Displace_Bytes(W1);
  889.       if Tmp = 0 then Error(Chi, 'TBYTE not Permitted');
  890.       end
  891.     else Error(Chi, 'DWORD, QWORD, or TBYTE Req''d');
  892.     end
  893.   else if St_St then
  894.     InsertHi_Low(Tmp+Sti_val)
  895.   else ErrIncorrect;
  896.   end;
  897. FldType := Rslt;
  898. end;
  899.  
  900. {-------------FildType}
  901. FUNCTION FildType : Boolean;
  902.   {do fild,fist,fistp-- 0..2}
  903. Type
  904.   Arraytype = Array[0..2, WPtr..QwPtr] of Word;
  905.   Table = Array[0..2, 0..4] of Char;
  906. Var Indx, Tmp : Integer;
  907.   Rslt : Boolean;
  908. Const
  909.   Fildarray : Arraytype = (
  910.     ($DF00, $DB00, $DF28),
  911.     ($DF10, $DB10, 0),
  912.     ($DF18, $DB18, $DF38));
  913.   Fildtable : Table = ('FILD ', 'FIST ', 'FISTP');
  914. begin
  915. Rslt := MatchSt(Fildtable, 5, 2, Indx);
  916. if Rslt then
  917.   begin
  918.   NextA;
  919.   if MemReg(W1) then
  920.     begin
  921.     if (ByWord >= WPtr) and (ByWord <= QwPtr) then
  922.       begin
  923.       InsertWait;       {fwait}
  924.       Tmp := Fildarray[Indx, ByWord];
  925.       InsertHi_Low(Tmp+ModeByte);
  926.       Displace_Bytes(W1);
  927.       if Tmp = 0 then Error(Chi, 'QWORD not Permitted');
  928.       end
  929.     else Error(Chi, 'WORD, DWORD, or QWORD Req''d');
  930.     end
  931.   else ErrIncorrect;
  932.   end;
  933. FildType := Rslt;
  934. end;
  935.  
  936. {-------------FaddType}
  937. FUNCTION FaddType : Boolean;
  938.   {The fadd,fmul,fcom,fcomp,fsub,fsubr,fdiv,fdivr instructions}
  939. Var Indx : Integer;
  940.   Rslt : Boolean;
  941. Type Table = Array[0..7, 0..4] of Char;
  942. Const Faddtable : Table = ('FADD ', 'FMUL ', 'FCOM ', 'FCOMP',
  943.   'FSUB ', 'FSUBR', 'FDIV ', 'FDIVR');
  944. begin
  945. Rslt := False;
  946. if MatchSt(Faddtable, 5, 7, Indx) then
  947.   begin
  948.   NoAddrs := True;
  949.   Rslt := True;
  950.   NextA;
  951.   InsertWait;           {fwait}
  952.   if MemReg(W1) then
  953.     begin
  954.     if ByWord = DwPtr then InsertByte($D8)
  955.     else if ByWord = QwPtr then InsertByte($DC)
  956.     else Error(Chi, 'DWORD or QWORD Req''d');
  957.     InsertByte(ModeByte+8*Indx);
  958.     Displace_Bytes(W1);
  959.     end
  960.   else if St_St then        {Must be st,st(i) or st(i),st }
  961.     begin
  962.     if St_first or (Indx = 2 {fcom} ) or (Indx = 3 {fcomp} ) then
  963.     InsertByte($D8) else InsertByte($DC);
  964.     ModeByte := $C0+8*Indx+Sti_val;
  965.     if not St_first and (Indx >= 6 {fdiv} ) then
  966.       ModeByte := ModeByte Xor 8; {reverse fdiv,fdivr for not st_first}
  967.     InsertByte(ModeByte);
  968.     end
  969.   else ErrIncorrect;
  970.   end;
  971. FaddType := Rslt;
  972. end;
  973.  
  974. {-------------FiaddType}
  975. FUNCTION FiaddType : Boolean;
  976.   {the fiadd,fimul,ficom,ficomp,fisub,fisubr,fidiv,fidivr instructions}
  977. Type Table = Array[0..7, 0..5] of Char;
  978. Var Indx : Integer;
  979.   Rslt : Boolean;
  980. Const Fiaddtable : Table = ('FIADD ', 'FIMUL ', 'FICOM ', 'FICOMP',
  981.   'FISUB ', 'FISUBR', 'FIDIV ', 'FIDIVR');
  982. begin
  983. Rslt := False;
  984. if MatchSt(Fiaddtable, 6, 7, Indx) then
  985.   begin
  986.   NoAddrs := True;
  987.   Rslt := True;
  988.   NextA;
  989.   if MemReg(W1) then
  990.     begin
  991.     InsertWait;         {fwait}
  992.     if ByWord = DwPtr then InsertByte($DA)
  993.     else if ByWord = WPtr then InsertByte($DE)
  994.     else Error(Chi, 'WORD or DWORD Req''d');
  995.     InsertByte(ModeByte+8*Indx);
  996.     Displace_Bytes(W1);
  997.     end
  998.   else ErrIncorrect;
  999.   end;
  1000. FiaddType := Rslt;
  1001. end;
  1002.  
  1003. {-------------Fnoperand}
  1004. FUNCTION Fnoperand : Boolean;
  1005.   {do the Fl Pt no operand instructions}
  1006. Type Table = Array[0..32, 0..6] of Char;
  1007. Var Indx : Integer;
  1008.   Rslt : Boolean;
  1009. Const
  1010.   Fnoptable : Table =       {Ordered with fnopcode}
  1011.    ('FNOP   ', 'FCHS   ', 'FABS   ', 'FTST   ', 'FXAM   ',
  1012.     'FLD1   ', 'FLDL2T ', 'FLDL2E ', 'FLDPI  ', 'FLDLG2 ', 'FLDLN2 ',
  1013.     'FLDZ   ', 'F2XM1  ', 'FYL2X  ', 'FPTAN  ', 'FPATAN ', 'FXTRACT',
  1014.     'FDECSTP', 'FINCSTP', 'FPREM  ', 'FYL2XP1', 'FSQRT  ', 'FRNDINT',
  1015.     'FSCALE ', 'FENI   ', 'FDISI  ', 'FCLEX  ', 'FINIT  ', 'FCOMPP ',
  1016.     'FNCLEX ', 'FNDISI ', 'FNENI  ', 'FNINIT ');
  1017.  
  1018.   Fnopcode : Array[0..32] of Word=
  1019.    ($D9D0, $D9E0, $D9E1, $D9E4, $D9E5, $D9E8,
  1020.     $D9E9, $D9EA, $D9EB, $D9EC, $D9ED, $D9EE,
  1021.     $D9F0, $D9F1, $D9F2, $D9F3, $D9F4, $D9F6,
  1022.     $D9F7, $D9F8, $D9F9, $D9FA, $D9FC, $D9FD,
  1023.     $DBE0, $DBE1, $DBE2, $DBE3, $DED9,
  1024.     $DBE2, $DBE1, $DBE0, $DBE3);
  1025.  
  1026. begin
  1027. Rslt := MatchSt(Fnoptable, 7, 32, Indx);
  1028. if Rslt then
  1029.   begin
  1030.   NextA;
  1031.   if Indx < 29 then InsertWait; {fwait}
  1032.   InsertHi_Low(Fnopcode[Indx]);
  1033.   end;
  1034. Fnoperand := Rslt;
  1035. end;
  1036.  
  1037. {-------------Register}
  1038. FUNCTION Register(Var R, W : Integer) : Boolean;
  1039. Type
  1040.   Regarytype = Array[0..15] of Array[1..2] of Char;
  1041. Const Regarray : Regarytype = (
  1042.   'AL', 'CL', 'DL', 'BL', 'AH', 'CH', 'DH', 'BH',
  1043.   'AX', 'CX', 'DX', 'BX', 'SP', 'BP', 'SI', 'DI');
  1044. Var Result_Reg : Boolean;
  1045. begin
  1046. Result_Reg := False;
  1047. if (Lsid[0] = Chr(2)) and (Sym = Identifier) then
  1048.   begin
  1049.   R := -1;
  1050.   repeat
  1051.     R := R+1;
  1052.   until (R > 15) or (ID2 = Regarray[R]);
  1053.   Result_Reg := R <= 15;
  1054.   if Result_Reg then
  1055.     begin
  1056.     NextA;
  1057.     if Sym = Comma then NextA;
  1058.     end;
  1059.   W := R div 8;             {w=1 for word type register}
  1060.   R := R and 7;
  1061.   end;
  1062. Register := Result_Reg;
  1063. end;
  1064.  
  1065. {-------------SegRegister}
  1066. FUNCTION SegRegister(Var R : Integer) : Boolean;
  1067. Var Result_Segr : Boolean;
  1068. begin
  1069. if (Sym = Identifier) and (Lsid[0] = Chr(2)) then
  1070.   begin
  1071.   Result_Segr := True;
  1072.   if ID2 = 'ES' then R := 0
  1073.   else if ID2 = 'CS' then R := 1
  1074.   else if ID2 = 'SS' then R := 2
  1075.   else if ID2 = 'DS' then R := 3
  1076.   else Result_Segr := False;
  1077.   if Result_Segr then
  1078.     begin
  1079.     NextA;
  1080.     if Sym = Comma then NextA;
  1081.     end;
  1082.   end
  1083. else Result_Segr := False;
  1084. SegRegister := Result_Segr;
  1085. end;
  1086.  
  1087. {-------------Data}
  1088. FUNCTION Data(Var Wd : Boolean) : Boolean;
  1089.   {See if immediate data is present.  Set wd if data found is word size}
  1090. Var SaveChi : Integer;
  1091.   Result : Boolean;
  1092. begin
  1093. Result := False; Wd := False;
  1094. SaveChi := OldChi;
  1095. with DataVal do
  1096.   begin
  1097.   Value := 0; Symb := False;
  1098.   while (Sym = Disp8) or (Sym = Disp16) do
  1099.     begin
  1100.     Result := True;
  1101.     if Symbol then
  1102.       begin
  1103.       if Cdecl then  {'&' in data symbol should be regarded as being 2 bytes}
  1104.         Wd := Wd or (Sym = Disp16) or (LSymname[1]='&')
  1105.       else
  1106.         Wd := Wd or (Sym = Disp16);
  1107.       Symb := True;
  1108.       Sname := LSymname;
  1109.       end
  1110.     else Value := Value+NValue;
  1111.     NextA; if Sym = Plus then NextA;
  1112.     end;
  1113.   Result := (Sym = EOLsym) and Result;
  1114.   Wd := Wd or not ByteSize(Value);
  1115.   end;
  1116. Data := Result;
  1117. if not Result then
  1118.   begin
  1119.   Chi := SaveChi-1; GetCh; NextA;
  1120.   end;
  1121. end;
  1122.  
  1123. {-------------TwoOperands}
  1124. FUNCTION TwoOperands : Boolean;
  1125.   {Handles codes with two operands}
  1126. Label 2;
  1127. Type InsType = (Mov, Adc, Addx, Andx, Cmp, Orx, Sbb, Sub, Xorx, Test, Xchg,
  1128.   Lds, Les, Lea);
  1129.   Nametype = Array[Mov..Lea] of Array[1..5] of Char;
  1130.   Codetype = Array[Mov..Lea] of Byte;
  1131.   Shcodetype = Array[Mov..Test] of Byte;
  1132. Var Inst : InsType;
  1133.   Tmp : Byte;
  1134.  
  1135. Const Instname : Nametype = (
  1136.   'MOV  ', 'ADC  ', 'ADD  ', 'AND  ', 'CMP  ', 'OR   ',
  1137.   'SBB  ', 'SUB  ', 'XOR  ', 'TEST ', 'XCHG ', 'LDS  ',
  1138.   'LES  ', 'LEA  ');
  1139.  
  1140.   Immedop : Codetype = ($C6, $80, $80, $80, $80, $80, $80, $80, $80, $F6, 0,
  1141.     0, 0, 0);
  1142.   Immedreg : Codetype = (0, $10, 0, $20, $38, 8, $18, $28, $30, 0, 0,
  1143.     0, 0, 0);
  1144.   Memregop : Codetype = ($88, $10, 0, $20, $38, 8, $18, $28, $30, $84, $86,
  1145.     $C5, $C4, $8D);
  1146.   Shimmedop : Shcodetype = (0, $14, 4, $24, $3C, $C, $1C, $2C, $34, $A8);
  1147.  
  1148.   FUNCTION ChkSignExt (MemRegWordSize, DataWordSize: Boolean): Byte;
  1149.   begin     {Thanx to Jim LeMay}{**}
  1150.   if (Immedop[Inst]=$80) and MemRegWordSize and not DataWordSize and
  1151.                          ShortSize(DataVal.Value) then
  1152.        ChkSignExt:=2            { the sign extension bit }
  1153.   else ChkSignExt:=0;           { no  sign extension bit }
  1154.   end;
  1155.  
  1156. begin TwoOperands := False;
  1157. for Inst := Mov to Lea do
  1158.   if Str = Instname[Inst] then
  1159.     GOTO 2;
  1160. Exit;                         {not found}
  1161. 2:                            {found}
  1162. NoAddrs := True;            {full address not acceptable}
  1163. TwoOperands := True;
  1164. NextA;
  1165. if Register(Reg1, W1) then
  1166.   begin
  1167.   if Register(Reg2, W2) then
  1168.     begin                   {mov reg,reg}
  1169.     if Inst >= Lds then Error(Chi, 'Register not Permitted');
  1170.     if W1 <> W2 then Error(Chi, 'Registers Incompatible');
  1171.     if (Inst = Xchg) and ((W1 = 1) and ((Reg1 = 0) or (Reg2 = 0))) then
  1172.       InsertByte($90+Reg1+Reg2)
  1173.     else
  1174.       begin
  1175.       InsertByte(Memregop[Inst]+W1);
  1176.       InsertByte($C0+Reg1+8*Reg2);
  1177.       end;
  1178.     end
  1179.   else if SegRegister(Reg2) then
  1180.     begin                   {mov reg,segreg}
  1181.     if (W1 = 0) or (Inst <> Mov) then SegmErr;
  1182.     InsertByte($8C); InsertByte($C0+8*Reg2+Reg1);
  1183.     end
  1184.   else if Data(WordSize) then
  1185.     begin                   {mov reg,data}
  1186.     if Inst >= Xchg then Error(Chi, 'Immediate not Permitted');
  1187.     if (Ord(WordSize) > W1) then DataLarge;
  1188.     SignExt := ChkSignExt(W1=1, WordSize);  {the sign extension bit}
  1189.     if (Inst = Mov) then
  1190.       begin
  1191.       InsertByte($B0+8*W1+Reg1);
  1192.       end
  1193.     else
  1194.       if (Reg1 = 0) {ax or al} then
  1195.         begin
  1196.         InsertByte(Shimmedop[Inst]+W1); {add ac,immed}
  1197.         SignExt := 0;                   {no sign extenstion for AL,AX}
  1198.         end
  1199.       else
  1200.         begin
  1201.         InsertByte(Immedop[Inst]+W1+SignExt);
  1202.         InsertByte($C0+Immedreg[Inst]+Reg1);
  1203.         end;
  1204.     Data_Bytes((SignExt = 0) and (W1 > 0));     {output the immediate data}
  1205.     end
  1206.   else if MemReg(W2) then
  1207.     begin                   {mov reg,mem/reg}
  1208.     if (Inst = Mov) and (Reg1 = 0) {ax or al} and (Rmm = 6) and (Md = 0) then
  1209.       begin                 {mov ac,mem}
  1210.       InsertByte($A0+W1);
  1211.       end
  1212.     else
  1213.       begin
  1214.       Tmp := Memregop[Inst];
  1215.       if Inst <= Xchg then
  1216.         begin
  1217.         Tmp := Tmp+W1;
  1218.         if Inst <> Test then Tmp := Tmp or 2; {to,from bit}
  1219.         end;
  1220.       InsertByte(Tmp);
  1221.       InsertByte(ModeByte+8*Reg1);
  1222.       end;
  1223.     Displace_Bytes(W2);     {add on any displacement bytes}
  1224.     end
  1225.   else ErrNull;
  1226.   end
  1227. else if SegRegister(Reg1) then
  1228.   begin
  1229.   if Inst <> Mov then SegmErr;
  1230.   InsertByte($8E);
  1231.   if Register(Reg2, W2) then
  1232.     begin                   {mov segreg,reg}
  1233.     if (W2 = 0) then WordReg;
  1234.     InsertByte($C0+8*Reg1+Reg2);
  1235.     end
  1236.   else if MemReg(W2) then
  1237.     begin                   {mov segreg,mem/reg}
  1238.     InsertByte(ModeByte+8*Reg1);
  1239.     Displace_Bytes(W2);     {add any displacement bytes}
  1240.     end
  1241.   else ErrNull;
  1242.   end
  1243. else if MemReg(W1) and (Inst <= Xchg) then
  1244.   begin
  1245.   if Register(Reg2, W2) then
  1246.     begin                   {mov mem/reg,reg}
  1247.     if (W2 > Ord(ByWord)) then Error(Chi, 'Byte Reg Exp');
  1248.     if (Inst = Mov) and (Reg2 = 0) {ax or al} and (Rmm = 6) and (Md = 0) then
  1249.       begin                 {mov ac, mem}
  1250.       InsertByte($A2+W2);
  1251.       end
  1252.     else
  1253.       begin
  1254.       InsertByte(Memregop[Inst]+W2);
  1255.       InsertByte(ModeByte+8*Reg2);
  1256.       end;
  1257.     Displace_Bytes(W1);
  1258.     end
  1259.   else if SegRegister(Reg2) then
  1260.     begin                   {mov mem/reg,segreg}
  1261.     if (Inst <> Mov) then SegmErr;
  1262.     InsertByte($8C); InsertByte(ModeByte+8*Reg2);
  1263.     Displace_Bytes(W1);
  1264.     end
  1265.   else if (Data(WordSize)) and (Inst < Xchg) then
  1266.     begin                   {mov mem/reg, data}
  1267.     Chk_BwPtr;
  1268.     if (Ord(WordSize) > Ord(ByWord)) then DataLarge;
  1269.     SignExt := ChkSignExt(ByWord=WPtr, WordSize);   {the sign extension bit}
  1270.     InsertByte(Immedop[Inst]+Ord(ByWord)+SignExt);
  1271.     InsertByte(ModeByte+Immedreg[Inst]);
  1272.     Displace_Bytes(W1);     {add displacement bytes}
  1273.     Data_Bytes((SignExt=0) and (ByWord = WPtr)); {the immediate data}
  1274.     end
  1275.   else ErrNull;
  1276.   end
  1277. else if (Sym = Disp8) or (Sym = Disp16) then
  1278.   Error(Chi, 'Immediate not Permitted')
  1279. else ErrNull;
  1280. end;
  1281.  
  1282. {-------------OneOperand}
  1283. FUNCTION OneOperand : Boolean;
  1284.   {Handles codes with one operand}
  1285. Type InsType = (Dec, Inc, Push, Pop, Nott, Neg);
  1286.   Nametype = Array[Dec..Neg] of Array[1..5] of Char;
  1287.   Codetype = Array[Dec..Neg] of Byte;
  1288. Var Inst : InsType;
  1289.   Pushpop : Boolean;
  1290.  
  1291. Const
  1292.   Instname : Nametype = (
  1293.      'DEC  ', 'INC  ', 'PUSH ', 'POP  ', 'NOT  ', 'NEG  ');
  1294.  
  1295.   Regop : Codetype = ($48, $40, $50, $58, 0, 0);
  1296.   Segregop : Codetype = (0, 0, 6, 7, 0, 0);
  1297.   Memregop : Codetype = ($FE, $FE, $FF, $8F, $F6, $F6);
  1298.   Memregcode : Codetype = ($8, 0, $30, 0, $10, $18);
  1299.  
  1300. begin OneOperand := False;
  1301. for Inst := Dec to Neg do
  1302.   if Str = Instname[Inst] then
  1303.     begin
  1304.     Pushpop := (Inst = Push) or (Inst = Pop);
  1305.     NoAddrs := True;
  1306.     OneOperand := True;
  1307.     NextA;
  1308.     if Register(Reg1, W1) then
  1309.       begin
  1310.       if (W1 = 1) and (Inst < Nott) then
  1311.         begin               {16 bit register instructions}
  1312.         InsertByte(Regop[Inst]+Reg1);
  1313.         end
  1314.       else begin            {byte register or neg,not with any reg}
  1315.       InsertByte(Memregop[Inst]+W1);
  1316.       InsertByte($C0+Memregcode[Inst]+Reg1);
  1317.       if Pushpop then
  1318.         WordReg;
  1319.       end
  1320.       end                   {if reg}
  1321.     else if SegRegister(Reg1) then
  1322.       begin                 {segment reg--push,pop only}
  1323.       InsertByte(Segregop[Inst]+8*Reg1);
  1324.       if not Pushpop then SegmErr
  1325.       end
  1326.     else if MemReg(W1) then
  1327.       begin                 {memreg  (not register)}
  1328.       if not Pushpop then Chk_BwPtr;
  1329.       InsertByte(Memregop[Inst] or Ord(ByWord));
  1330.       InsertByte(ModeByte+Memregcode[Inst]);
  1331.       Displace_Bytes(W1);
  1332.       end
  1333.     else ErrIncorrect;
  1334.     end;                    {if st}
  1335. end;
  1336.  
  1337. {-------------NoOperand}
  1338. FUNCTION NoOperand : Boolean;
  1339.   {Those instructions consisting only of opcode}
  1340. Const Nmbsop = 31;
  1341. Type Sofield = Array[0..Nmbsop] of Array[1..5] of Char;
  1342.   Opfield = Array[0..Nmbsop] of Byte;
  1343. Var Index : Integer;
  1344. Const
  1345.   Sop : Sofield = (
  1346.     'DAA  ', 'AAA  ', 'NOP  ', 'MOVSB', 'MOVSW', 'CMPSB', 'CMPSW',
  1347.     'XLAT ', 'HLT  ',
  1348.     'CMC  ', 'DAS  ', 'AAS  ', 'CBW  ', 'CWD  ', 'PUSHF',
  1349.     'POPF ', 'SAHF ', 'LAHF ', 'STOSB', 'STOSW', 'LODSB', 'LODSW',
  1350.     'SCASB', 'SCASW', 'INTO ', 'IRET ', 'CLC  ', 'STC  ', 'CLI  ',
  1351.     'STI  ', 'CLD  ', 'STD  ');
  1352.   Opcode : Opfield = (
  1353.     $27, $37, $90, $A4, $A5, $A6, $A7, $D7, $F4,
  1354.     $F5, $2F, $3F, $98, $99, $9C, $9D, $9E, $9F, $AA, $AB, $AC, $AD,
  1355.     $AE, $AF, $CE, $CF, $F8, $F9, $FA, $FB, $FC, $FD);
  1356.  
  1357. begin NoOperand := False;
  1358. for Index := 0 to Nmbsop do
  1359.   if Str = Sop[Index] then
  1360.     begin
  1361.     InsertByte(Opcode[Index]);
  1362.     NoOperand := True;
  1363.     NextA;
  1364.     Exit;
  1365.     end;
  1366. end;
  1367.  
  1368. {-------------Prefix}
  1369. FUNCTION Prefix : Boolean;
  1370.   {process the prefix instructions}
  1371. Const Nmbsop = 11;
  1372. Type Field = Array[0..Nmbsop] of String5;
  1373.   Opfield = Array[0..Nmbsop] of Byte;
  1374. Var Index : Integer;
  1375.     SaveWait : Boolean;
  1376.     Opc : Byte;
  1377. Const
  1378.   Ops : Field = (
  1379.     'LOCK ', 'REP  ', 'REPZ ',
  1380.     'REPNZ', 'REPE ', 'REPNE', 'WAIT ', 'FWAIT',
  1381.     'ES   ', 'DS   ', 'CS   ', 'SS   ');
  1382.   Opcode : Opfield = (
  1383.     $F0, $F2, $F3, $F2, $F3, $F2, $9B, $9B, $26, $3E, $2E, $36);
  1384.  
  1385. begin Prefix := False;
  1386. for Index := 0 to Nmbsop do
  1387.   if Str = Ops[Index] then
  1388.     begin
  1389.     Opc:=Opcode[Index];
  1390.     SaveWait := Wait_Already;  {save any WAIT already programed}
  1391.     InsertByte(Opc);
  1392.     Wait_Already:=SaveWait or (Opc=$9B); {set for WAIT or FWAIT}
  1393.     Tindex0 := Tindex;      {for future fix ups}
  1394.     if UCh = ':' then GetCh; {es: etc permitted with a colon}
  1395.     Prefix := True;
  1396.     Exit;
  1397.     end;
  1398. end;
  1399.  
  1400. {-------------FindLabel}
  1401. FUNCTION FindLabel(Var B : Integer) : Boolean;
  1402.   {Find a label if it exists in the label chain}
  1403. Var Found : Boolean;
  1404. begin
  1405. Pl := Firstlabel; Found := False;
  1406. while (Pl <> Nil) and not Found do
  1407.   with Pl^ do
  1408.     if Symname = Name then
  1409.       begin
  1410.       Found := True;
  1411.       B := ByteCnt;
  1412.       end
  1413.     else Pl := Next;
  1414. FindLabel := Found;
  1415. end;
  1416.  
  1417. {-------------ShortJmp}
  1418. FUNCTION ShortJmp : Boolean;
  1419.   {short jump instructions}
  1420. Const Numjmp = 34;
  1421. Type
  1422.   Sjfield = Array[0..Numjmp] of Array[1..5] of Char;
  1423.   Opfield = Array[0..Numjmp] of Byte;
  1424. Var I, B : Integer;
  1425. Const
  1426.   Jumps : Sjfield = (
  1427.     'JO   ', 'JNO  ', 'JB   ', 'JNAE ', 'JNB  ', 'JAE  ',
  1428.     'JE   ', 'JZ   ', 'JNE  ', 'JNZ  ', 'JBE  ', 'JNA  ',
  1429.     'JNBE ', 'JA   ', 'LOOPN', 'LOOPZ', 'LOOPE', 'LOOP ',
  1430.     'JCXZ ', 'JS   ', 'JNS  ', 'JP   ', 'JPE  ', 'JNP  ',
  1431.     'JPO  ', 'JL   ', 'JNGE ', 'JNL  ', 'JGE  ', 'JLE  ',
  1432.     'JNG  ', 'JNLE ', 'JG   ', 'JC   ', 'JNC  ');
  1433.  
  1434.   Opcode : Opfield = (
  1435.     $70, $71, $72, $72, $73, $73, $74, $74, $75, $75, $76, $76,
  1436.     $77, $77, $E0, $E1, $E1, $E2, $E3, $78, $79, $7A, $7A, $7B,
  1437.     $7B, $7C, $7C, $7D, $7D, $7E, $7E, $7F, $7F, $72, $73);
  1438.  
  1439. begin ShortJmp := False;
  1440. for I := 0 to Numjmp do
  1441.   if Str = Jumps[I] then
  1442.     begin
  1443.     InsertByte(Opcode[I]);
  1444.     ShortJmp := True;
  1445.     NoAddrs := True;
  1446.     NextA;
  1447.     if Sym = Identifier then
  1448.       begin
  1449.       if FindLabel(B) then
  1450.         begin
  1451.         Addr := B-(ByteCount+1);
  1452.         if (Addr <= $7F) and (Addr >= -128) then InsertByte(Lo(Addr))
  1453.         else Error(Chi, 'Too Far');
  1454.         end
  1455.       else
  1456.         begin               {enter jump into fixups}
  1457.         New(Pf);
  1458.         with Pf^ do
  1459.           begin
  1460.           Next := Firstfix;
  1461.           if Firstfix <> Nil then
  1462.             Firstfix^.Prev := Pf;
  1463.           Firstfix := Pf;
  1464.           Prev := Nil;
  1465.           Jmptype := Short;
  1466.           Name := Symname;
  1467.           Fix_pt := ByteCount; Indx := Tindex;
  1468.           InsertByte(0);     {dummy insertion}
  1469.           end;
  1470.         end;
  1471.       NextA;
  1472.       end
  1473.     else Error(Chi, 'Label Exp');
  1474.     end;
  1475. end;
  1476.  
  1477. {-------------ShfRot}
  1478. FUNCTION ShfRot : Boolean;
  1479. Type
  1480.   InsType = (Rclx, Rcrx, Rolx, Rorx, Salx, Sarx, Shlx, Shrx);
  1481.   Nametype = Array[Rclx..Shrx] of Array[1..3] of Char;
  1482.   Codetype = Array[Rclx..Shrx] of Byte;
  1483. Var
  1484.   Inst : InsType;
  1485.   CL : Byte;
  1486.  
  1487. Const
  1488.   Instname : Nametype = (
  1489.     'RCL', 'RCR', 'ROL', 'ROR', 'SAL', 'SAR',
  1490.     'SHL', 'SHR');
  1491.  
  1492.   Regcode : Codetype = ($10, $18, 0, 8, $20, $38, $20, $28);
  1493.  
  1494. begin ShfRot := False;
  1495. if Lsid[0] = Chr(3) then
  1496.   for Inst := Rclx to Shrx do
  1497.     if ID3 = Instname[Inst] then
  1498.       begin
  1499.       NoAddrs := True; ShfRot := True;
  1500.       NextA;
  1501.       InsertByte($D0);       {may get modified later}
  1502.       if Register(Reg1, W1) then
  1503.         InsertByte($C0+Regcode[Inst]+Reg1)
  1504.       else if MemReg(W2) then
  1505.         begin
  1506.         Chk_BwPtr;
  1507.         W1 := Ord(ByWord);
  1508.         InsertByte(ModeByte+Regcode[Inst]);
  1509.         Displace_Bytes(W2);
  1510.         end
  1511.       else Error(Chi, 'Reg or Mem Exp');
  1512.       if Sym = Comma then NextA;
  1513.       CL := 0;
  1514.       if (Sym=Identifier) and (ID3 = 'CL ') then CL := 2
  1515.       else if NValue <> 1 then Error(Chi, 'CL or 1 Exp');
  1516.       NextA;
  1517.       Modify_Byte(Tindex0, CL+W1); {modify the opcode}
  1518.       end;
  1519. end;
  1520.  
  1521. {-------------CallJmp}
  1522. FUNCTION CallJmp : Boolean;
  1523. Type InsType = (CALL, JMP);
  1524.   Codetype = Array[CALL..JMP] of Byte;
  1525. Var
  1526.   Inst : InsType;
  1527.   Dist : (Nodist, Long, Shrt, Near);
  1528.   Tmp : Byte;
  1529.   Dwtmp : PtrType;
  1530.   B : Integer;
  1531.   WordSize : Boolean;
  1532.  
  1533. Const
  1534.   Shortop : Codetype = ($E8, $E9);
  1535.   Longop : Codetype = ($9A, $EA);
  1536.   Longcode : Codetype = ($18, $28);
  1537.   Shortcode : Codetype = ($10, $20);
  1538.  
  1539. begin CallJmp := False;
  1540. if Str = 'CALL ' then Inst := CALL
  1541. else if Str = 'JMP  ' then Inst := JMP
  1542. else Exit;
  1543.  
  1544. CallJmp := True;
  1545. NextA;
  1546. Dist := Nodist;
  1547. Dwtmp := ByWord;            {could have passed a 'DWORD PTR' here}
  1548. if Sym = JmpDist then
  1549.   begin
  1550.   if ID2 = 'FA' then Dist := Long
  1551.   else if ID2 = 'NE' then Dist := Near
  1552.   else if ID2 = 'SH' then Dist := Shrt;
  1553.   NextA;
  1554.   end;
  1555. if (Sym = Address) then
  1556.   begin
  1557.   InsertByte(Longop[Inst]);
  1558.   InsertWord(NValue);
  1559.   InsertWord(Segm);
  1560.   end
  1561. else if Register(Reg1, W1) then
  1562.   begin
  1563.   if W1 = 0 then WordReg;
  1564.   if Dist = Long then Error(Chi, 'FAR not Permitted');
  1565.   InsertByte($FF);
  1566.   InsertByte($C0+Shortcode[Inst]+Reg1);
  1567.   end
  1568. else if Sym = Identifier then
  1569.   begin
  1570.   if Dist = Long then Error(Chi, 'Far not Permitted with Label');
  1571.   if FindLabel(B) then
  1572.     begin
  1573.     Addr := B-(ByteCount+2);
  1574.     if Inst = CALL then
  1575.       begin
  1576.       InsertByte($E8);
  1577.       InsertWord(Addr-1);
  1578.       end
  1579.     else
  1580.       if (Addr <= $7F) and (Addr >= -128) and (Dist <> Near) then   {inst=jmp}
  1581.         begin               {short jump}
  1582.         InsertByte($EB); InsertByte(Lo(Addr));
  1583.         end
  1584.       else
  1585.         begin
  1586.         InsertByte($E9); InsertWord(Addr-1);
  1587.         end;
  1588.     end                     {findlabel}
  1589.   else
  1590.     begin                   {enter it into fixup chain}
  1591.     New(Pf);
  1592.     with Pf^ do
  1593.       begin
  1594.       Next := Firstfix;
  1595.       if Firstfix <> Nil then
  1596.         Firstfix^.Prev := Pf;
  1597.       Firstfix := Pf;
  1598.       Prev := Nil;
  1599.       Name := Symname;
  1600.       if Dist = Shrt then
  1601.         begin
  1602.         Jmptype := Short;
  1603.         InsertByte($EB);
  1604.         Fix_pt := ByteCount; Indx := Tindex;
  1605.         InsertByte(0);       {dummy insertion}
  1606.         end
  1607.       else
  1608.         begin
  1609.         Jmptype := Med;
  1610.         if Inst = CALL then InsertByte($E8) else InsertByte($E9);
  1611.         Fix_pt := ByteCount; Indx := Tindex;
  1612.         InsertByte(0);       {dummy insertion}
  1613.         Indx2 := Tindex;
  1614.         InsertByte(0);       {another dummy byte}
  1615.         end;
  1616.       end;
  1617.     end;
  1618.   end                       {identifier}
  1619. else if Data(WordSize) then
  1620.   begin  {Direct CALL or JMP}
  1621.   if (Inst=JMP) and (Dist=Shrt) then
  1622.     begin
  1623.     if WordSize then Error(Chi,'Must be byte size');
  1624.     InsertByte($EB);
  1625.     Data_Bytes(False);
  1626.     end
  1627.   else
  1628.     begin
  1629.     if not ((Dist=Nodist) or (Dist=Near)) or (Dwtmp<>UnkPtr) then
  1630.       Error(Chi, 'Only NEAR permitted');
  1631.     if not WordSize then Error(Chi, 'Must be word size');
  1632.     InsertByte(Shortop[Inst]);
  1633.     Data_Bytes(True);
  1634.     end;
  1635.   end
  1636. else if MemReg(W1) then
  1637.   begin
  1638.   if (Dist = Long) or (Dwtmp = DwPtr) then Tmp := Longcode[Inst]
  1639.   else Tmp := Shortcode[Inst];
  1640.   InsertByte($FF);
  1641.   InsertByte(ModeByte+Tmp);
  1642.   Displace_Bytes(W1);
  1643.   end
  1644. else ErrNull;
  1645. NextA;
  1646. end;
  1647.  
  1648. {-------------Retrn}
  1649. PROCEDURE Retrn(Far : Boolean);
  1650. begin
  1651. if (Sym = Disp16) or (Sym = Disp8) then
  1652.   begin
  1653.   if Far then InsertByte($CA) else InsertByte($C2);
  1654.   InsertWord(NValue);
  1655.   NextA;
  1656.   end
  1657. else
  1658.   if Far then InsertByte($CB) else InsertByte($C3);
  1659. end;
  1660.  
  1661. {-------------OtherInst}
  1662. FUNCTION OtherInst : Boolean;
  1663. Label 2, 10, 20, 30;
  1664. Type
  1665.   Instsym = (Ret, Retf, Aam, Aad, Inn, Out, Mul, Imul, Divd, Idiv, Int);
  1666.   Nametype = Array[Ret..Int] of Array[1..5] of Char;
  1667. Var Index : Instsym;
  1668.   Tmp : Byte;
  1669. Const Instname : Nametype = (
  1670.   'RET  ', 'RETF ', 'AAM  ', 'AAD  ', 'IN   ', 'OUT  ', 'MUL  ',
  1671.   'IMUL ', 'DIV  ', 'IDIV ', 'INT  ');
  1672.  
  1673.   PROCEDURE MulDiv(B : Byte);
  1674.   Var Wordbit : Integer;
  1675.   begin
  1676.   InsertByte($F6);
  1677.   if Register(Reg2, W2) then
  1678.     begin
  1679.     InsertByte($C0+B+Reg2);
  1680.     Wordbit := W2;
  1681.     end
  1682.   else if MemReg(W2) then
  1683.     begin
  1684.     Chk_BwPtr;
  1685.     Wordbit := Ord(ByWord);
  1686.     InsertByte(ModeByte+B);
  1687.     Displace_Bytes(W2);
  1688.     end
  1689.   else Error(Chi, 'Reg or Mem Exp');
  1690.   Modify_Byte(Tindex0, Wordbit);
  1691.   end;
  1692.  
  1693.   FUNCTION DXreg : Boolean;
  1694.   begin
  1695.   DXreg := False;
  1696.   if Sym = Identifier then
  1697.     if ID2 = 'DX' then
  1698.       begin DXreg := True; NextA; end;
  1699.   end;
  1700.  
  1701.   FUNCTION Accum(Var W : Integer) : Boolean;
  1702.   Var Result_acc : Boolean;
  1703.     {See if next is AL or AX}
  1704.   begin
  1705.   Result_acc := False;
  1706.   if (Sym = Identifier) then
  1707.     begin
  1708.     Result_acc := (ID3 = 'AX ') or (ID3 = 'AL ');
  1709.     if Result_acc then
  1710.       begin
  1711.       if Str[2] = 'X' then W := 1 else W := 0; {word vs byte register}
  1712.       NextA;
  1713.       end;
  1714.     end;
  1715.   Accum := Result_acc;
  1716.   end;
  1717.  
  1718. begin
  1719. OtherInst := False;
  1720. for Index := Ret to Int do
  1721.   if Str = Instname[Index] then GOTO 2;
  1722. Exit;
  1723.  
  1724. 2: OtherInst := True; NextA;
  1725. case Index of
  1726.   Ret : Retrn(False);
  1727.   Retf : Retrn(True);
  1728.   Out : begin
  1729.         if DXreg then InsertByte($EE) {out dx,ac}
  1730.         else if Sym = Disp8 then
  1731.           begin             {out port,ac}
  1732.           InsertByte($E6);
  1733.           InsertByte(Lo(NValue));
  1734.           NextA;
  1735.           end
  1736.         else GOTO 10;
  1737.         if Sym = Comma then NextA;
  1738.         if Accum(W1) then
  1739.           Modify_Byte(Tindex0, W1) {al or ax}
  1740.         else GOTO 20;
  1741.         end;
  1742.   Inn : begin
  1743.         if Accum(W1) then
  1744.           begin
  1745.           if Sym = Comma then NextA;
  1746.           if DXreg then InsertByte($EC+W1) {in ac,dx}
  1747.           else
  1748.             begin
  1749.             if Sym = Disp8 then
  1750.               begin         {in ac,port}
  1751.               InsertByte($E4+W1);
  1752.               InsertByte(Lo(NValue));
  1753.               NextA;
  1754.               end
  1755.             else
  1756. 10:            Error(Chi, 'DX or Port Exp');
  1757.             end
  1758.           end
  1759.         else
  1760. 20:         Error(Chi, 'AX or AL Exp');
  1761.         end;
  1762.   Aam : begin
  1763.         Tmp := $D4;
  1764.         GOTO 30;
  1765.         end;
  1766.   Aad : begin
  1767.         Tmp := $D5;
  1768. 30:     InsertByte(Tmp);
  1769.         InsertByte($A);
  1770.         end;
  1771.   Mul : MulDiv($20);
  1772.   Imul : MulDiv($28);
  1773.   Divd : MulDiv($30);
  1774.   Idiv : MulDiv($38);
  1775.   Int : begin
  1776.         if Sym = Disp8 then
  1777.           begin
  1778.           if NValue = 3 then InsertByte($CC)
  1779.           else
  1780.             begin
  1781.             InsertByte($CD);
  1782.             InsertByte(Lo(NValue));
  1783.             end;
  1784.           NextA;
  1785.           end
  1786.         else ErrNull;
  1787.         end;
  1788.  end;
  1789. end;
  1790.  
  1791. {-------------GetQuoted}
  1792. FUNCTION GetQuoted(Var Ls : BigString) : Boolean;
  1793. Var SaveChi, K : Integer;
  1794.   Term : Char;
  1795.   Gq : Boolean;
  1796. begin
  1797. SkipSpaces;
  1798. SaveChi := Chi; K := 1;
  1799. Gq := False;
  1800. if (UCh = '''') or (UCh = '"') then
  1801.   begin
  1802.   Term := UCh; GetCh;
  1803.   while (UCh <> Term) and (UCh <> Chr(CR)) do
  1804.     if (UCh <> Chr(CR)) and (K <= BigStringSize) then
  1805.       begin
  1806.       Ls[K] := LCh; K := K+1; GetCh;
  1807.       end;
  1808.   GetCh;                    {pass by term}
  1809.   Gq := not(UCh in ['+', '-', '*', '/']); {else was meant to be expr}
  1810.   end;
  1811. Ls[0] := Chr(K-1);
  1812. if not Gq then
  1813.   begin Chi := SaveChi-1; GetCh; end;
  1814. GetQuoted := Gq;
  1815. end;
  1816.  
  1817. {-------------DataByte}
  1818. PROCEDURE DataByte;
  1819. Var I : Integer;
  1820.   Lst : BigString;
  1821. begin
  1822. repeat
  1823.   if GetQuoted(Lst) then
  1824.     begin
  1825.     for I := 1 to Ord(Lst[0]) do
  1826.       InsertByte(Lo(Ord(Lst[I])));
  1827.     end
  1828.   else
  1829.     if ReadByte then InsertByte(Byt)
  1830.     else begin ErrNull; end;
  1831.   while (UCh = ' ') or (UCh = Chr(Tab)) or (UCh = ',') do GetCh;
  1832. until (UCh = Chr(CR)) or (UCh = ';') or Aerr;
  1833. NextA;
  1834. end;
  1835.  
  1836. {-------------Chk_For_Label}
  1837. PROCEDURE Chk_For_Label;
  1838. Var Dum1,Dum2 : Integer;
  1839. begin
  1840. if not Prefix then          {could be prefix here}
  1841.   begin
  1842.   SkipSpaces;
  1843.   if (Lsid[0] > Chr(0)) and (UCh = ':') then
  1844.     begin                 {label found}
  1845.     Sym := Identifier;
  1846.     if Register(Dum1,Dum2) then Error(Chi, 'Register name used as label')
  1847.     else
  1848.       begin
  1849.       GetCh; Symname := Lsid;
  1850.       Pl := Firstlabel;       {check for duplication of label}
  1851.       while Pl <> Nil do
  1852.         with Pl^ do
  1853.           begin
  1854.           if Symname = Name then Error(Chi, 'Duplicate Label');
  1855.           Pl := Next;
  1856.           end;
  1857.       New(Pl);                {add the label to the label chain}
  1858.       with Pl^ do
  1859.         begin
  1860.         Next := Firstlabel;
  1861.         Firstlabel := Pl;
  1862.         ByteCnt := ByteCount;
  1863.         Name := Symname;
  1864.         end;
  1865.       Pf := Firstfix;         {see if any fixups are required}
  1866.       while Pf <> Nil do
  1867.         with Pf^ do
  1868.           begin
  1869.           if Name = Symname then
  1870.             begin             {remove this fixup from chain}
  1871.             if Pf = Firstfix then
  1872.               Firstfix := Next
  1873.             else Prev^.Next := Next;
  1874.             if Next <> Nil then Next^.Prev := Prev;
  1875.             Dispose(Pf);
  1876.             Addr := ByteCount-(Fix_pt+1);
  1877.             if Jmptype = Short then
  1878.               begin
  1879.               if Addr+$80 <= $FF then Modify_Byte(Indx, Lo(Addr))
  1880.               else Error(Chi, 'Too Far');
  1881.               end
  1882.             else
  1883.               begin           {jmptype=med}
  1884.               Addr := Addr-1;
  1885.               Modify_Byte(Indx, Lo(Addr));
  1886.               Modify_Byte(Indx2, Hi(Addr));
  1887.               end;
  1888.             end;
  1889.           Pf := Next;
  1890.           end;
  1891.       end;                    {label found}
  1892.     GetString;              {for next item to use}
  1893.     end;
  1894.   end                       {neither a label or a prefix}
  1895. else GetString;             {it was a prefix}
  1896. end;
  1897.  
  1898. {-------------Interpret}
  1899. PROCEDURE Interpret;
  1900. begin
  1901. Tindex0 := Tindex;          {opcode position}
  1902. GetString;
  1903. Chk_For_Label;
  1904. while Prefix do             {process any prefix instructions}
  1905.   GetString;
  1906. if Lsid[0] > Chr(0) then
  1907.   begin
  1908.   if not NoOperand then
  1909.   if not OneOperand then
  1910.   if not TwoOperands then
  1911.   if not ShortJmp then
  1912.   if not CallJmp then
  1913.   if not ShfRot then
  1914.   if not OtherInst then
  1915.   if not FaddType then
  1916.   if not Fnoperand then
  1917.   if not FiaddType then
  1918.   if not FldType then
  1919.   if not FmemOnly then
  1920.   if not FildType then
  1921.   if not FstiOnly then
  1922.   if ID3 = 'DB ' then DataByte
  1923.   else if Lsid = 'NEW' then begin NewFnd:=True; NextA; end
  1924.   else if Lsid = 'END' then
  1925.     begin
  1926.     TheEnd := True;
  1927.     NextA;
  1928.     end
  1929.   else Error(Chi, 'Unknown Instruction');
  1930.   end
  1931. else
  1932.   NextA;                 {if not a string find out what}
  1933. if Sym <> EOLsym then Error(Chi, 'End of Line Exp');
  1934. end;
  1935.  
  1936. {-------------Chk_IOerror}
  1937. FUNCTION Chk_IOerror(S : FileString): Integer;
  1938. Var IOerr : Integer;
  1939. begin
  1940. IOerr := IOResult;
  1941. if (IOerr = 2) or (IOerr = 3) then WriteLn('Can''t find ', S)
  1942. else if IOerr <> 0 then WriteLn('I/O Error ', Hex4(IOerr));
  1943. Chk_IOerror := IOerr;
  1944. end;
  1945.  
  1946. {-------------PromptForInput}
  1947. PROCEDURE PromptForInput;
  1948. Var
  1949.   InName,Name : FileString;
  1950.   Err : Integer;
  1951. begin
  1952. {$I-}
  1953. repeat
  1954.   Write('Source Filename [.ASM]: '); ReadLn(InName);
  1955.   if InName='' then Halt;
  1956.   DefaultExtension('ASM', InName, Name);
  1957.   Assign(Inn, InName); Reset(Inn);
  1958.   Err:=Chk_IOerror(InName);
  1959.   if Err>1 then Halt(1);
  1960. until Err=0;
  1961. Write('Object Filename [', Name, '.INL]: '); ReadLn(InName);
  1962. if InName='' then InName:=Name;   {Use the same name}
  1963. DefaultExtension('INL',InName,Name);
  1964. Assign(Out, InName);
  1965. Rewrite(Out);
  1966. if Chk_IOerror(InName)<>0 then Halt(1);
  1967. {$I+}
  1968. end;
  1969.  
  1970. {-------------CommandInput}
  1971. PROCEDURE CommandInput(StartParam : Integer);
  1972. Var
  1973.   InName,Name : FileString;
  1974. begin
  1975. InName:=ParamStr(StartParam);
  1976. DefaultExtension('ASM', InName, Name);
  1977. {$I-}
  1978. Assign(Inn, InName);
  1979. Reset(Inn);
  1980. if Chk_IOerror(InName)<>0 then Halt(1);
  1981. if ParamCount > StartParam then InName:=ParamStr(StartParam+1)
  1982.   else InName:=Name;             {Use the old name}
  1983. DefaultExtension('INL',InName,Name);
  1984. Assign(Out, InName);
  1985. Rewrite(Out);
  1986. if Chk_IOerror(InName)<>0 then Halt(1);
  1987. {$I+}
  1988. end;
  1989.  
  1990. {-------------LabelReport}
  1991. PROCEDURE LabelReport;  {Report any fixups not made and restore heap}
  1992. Var
  1993.   Pftmp : Fixup_Info_Ptr;
  1994.   Pltmp : Label_Info_ptr;
  1995. begin
  1996. Pf := Firstfix;
  1997. while Pf <> Nil do
  1998.   with Pf^ do
  1999.     begin
  2000.     WriteLn('Label not Found-- ', Name);
  2001.     Pftmp := Next;
  2002.     Dispose(Pf);
  2003.     Pf:=Pftmp;
  2004.     end;
  2005. Pl := Firstlabel;
  2006. while Pl <> Nil do
  2007.   begin
  2008.   Pltmp := Pl^.Next;
  2009.   Dispose(Pl);
  2010.   Pl:=Pltmp;
  2011.   end;
  2012. end;
  2013.  
  2014. {-------------GetParameters}
  2015. PROCEDURE GetParameters;
  2016. Var
  2017.   Param : Integer;
  2018.   S : String[80];
  2019. begin
  2020. WriteLn(Signon1+Signon2);
  2021. if (ParamCount >= 1) then
  2022.   begin
  2023.   S := ParamStr(1);
  2024.   Param := 1;
  2025.   case S[1] of
  2026.     '/', '-' : if (UpCase(S[2]) = 'C') and (Length(S) = 2) then
  2027.                   begin      {Switch to C}
  2028.                   Cdecl := True;
  2029.                   InString := '__emit__('^M^J;
  2030.                   Separate := ',';
  2031.                   StartComment := '/*';
  2032.                   EndComment := '*/'^M^J;
  2033.                   HexLeader := '0x';
  2034.                   Param := 2;
  2035.                   end;
  2036.      else;
  2037.     end;
  2038.   end;
  2039. if ParamCount >= Param then CommandInput(Param) else PromptForInput;
  2040. end;
  2041.  
  2042. {-------------Main}
  2043. begin
  2044. GetParameters;
  2045. Wait_Already:=False;
  2046. NewFnd:=True;
  2047. while NewFnd and not EOF(Inn) do
  2048.   begin
  2049.   NewFnd:=False;
  2050.   Start_Col := 1; TheEnd := False;
  2051.   Tindex := 0;
  2052.   ByteCount := 0;
  2053.   Firstlabel := Nil; Firstfix := Nil;
  2054.   InsertStr(InString);
  2055.  
  2056.   while not EOF(Inn) and not TheEnd and not NewFnd do
  2057.     begin
  2058.     Aerr := False; NoAddrs := False;
  2059.     ByWord := UnkPtr;
  2060.     Column := 0;
  2061.     ReadLn(Inn, St); Chi := 1; GetCh; Sym := Othersym;
  2062.     SkipSpaces;
  2063.     if UCh<>Chr(CR) then   {skip blank lines}
  2064.       begin
  2065.       InsertStr('  ');
  2066.       Interpret;
  2067.       InsertChr(' ');   {Space for possible ');' fixup}
  2068.       if not NewFnd and not TheEnd then
  2069.         begin
  2070.         while Column < CommentColumn do InsertChr(' ');
  2071.         InsertStr(StartComment);
  2072.         I := 1;
  2073.         while (Column < 124) and (I <= Length(St)) do
  2074.           begin
  2075.           InsertChr(St[I]);
  2076.           I := I+1;
  2077.           end;
  2078.         InsertStr(EndComment);
  2079.         end;
  2080.       end;
  2081.     if EOF(Inn) or TheEnd or NewFnd then
  2082.       begin   {Fix up the last '/' or ',' inserted}
  2083.       TextArray[LastSlash]:=')';
  2084.       TextArray[Succ(LastSlash)]:=';';
  2085.       InsertStr(^M^J);
  2086.       end;
  2087.     end;
  2088.   LabelReport;       {report any fixups not made and dispose all heap items}
  2089.   for I := 0 to Tindex-1 do Write(Out, TextArray[I]);
  2090.   end;
  2091. Close(Out);
  2092. Close(Inn);
  2093. end.
  2094.